package com.comtrade.map;

import java.util.ArrayList;
import java.util.Vector;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.animation.TranslateAnimation;

import com.comtrade.ilserver.tasks.BeaconServer;
import com.comtrade.mathematics.BeaconRacun;

/*
 * TouchView showing map and user locaton
 * 
 */
public class TouchView extends View {

	private Drawable mMap;
	private Drawable mBeacon;
	private static float MIN_ZOOM = 1f;
	private static float MAX_ZOOM = 5f;
	private float scaleFactor = 1.f;
	private ScaleGestureDetector detector;
	private GestureDetector simpledetector;
	Matrix matrix;
	int height;
	int width;
	float ratio1;
	float ratio2;
	float scaleratio;

	float translatedX;
	float translatedY;

	public DotView mDot;

	public ArrayList<BeaconView> listBeacona = new ArrayList<BeaconView>();
	public BeaconView oneBeacon;
	private Vector<BeaconRacun> beaconPositions;
	private Rect clipBounds;

	public TouchView(Context context) {
		this(context, null, 0, new DotView(context));

	}

	public TouchView(Context context, AttributeSet attrs) {
		this(context, attrs, 0, new DotView(context));
	}

	public TouchView(Context context, DotView dot) {
		this(context, null, 0, dot);

	}

	/**
	 * Creates instance of touch view. It needs dotView to know that it exists
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 * @param dot
	 */

	public TouchView(Context context, AttributeSet attrs, int defStyle,
			DotView dot) {
		super(context, attrs, defStyle);
		// setBackgroundResource(R.drawable.plan);
		detector = new ScaleGestureDetector(getContext(), new ScaleListener());
		simpledetector = new GestureDetector(getContext(),
				simpleOnGestureListener);
		oneBeacon = new BeaconView(context, this);
		// mMap=getResources().getDrawable(R.drawable.plan);
		matrix = new Matrix();
		beaconPositions = new Vector<BeaconRacun>();
		mDot = new DotView(context, this);
		setDotCoordinates(50, 50);
		mDot.setH(50);
		mDot.setW(30);

	}

	public void CreateBeaconList(ArrayList<BeaconServer> bs) {
		for (BeaconServer beaconServer : bs) {
			BeaconView pBeacon = new BeaconView(getContext(), this);
			pBeacon.setxCoor(beaconServer.getX());
			pBeacon.setyCoor(beaconServer.getY());
			pBeacon.setPoruka(beaconServer.getMsg());
			listBeacona.add(pBeacon);
		}

	}

	/**
	 * Sets Drawable map as map image sets top left corner in (0, 0) and bottom
	 * right cornet to (w, h)
	 * 
	 * @param map
	 * @param w
	 * @param h
	 */
	public void setMap(Drawable map, int w, int h) {
		mMap = map;
		mMap.setBounds(0, 0, w, h);

		// getResizedBitmap(mMap, height, width);

	}

	public void getResizedBitmap(Drawable bm, int newHeight, int newWidth) {
		float width = mMap.getBounds().width();
		int height = mMap.getBounds().height();
		float scaleWidth = ((float) newWidth) / width;
		float scaleHeight = ((float) newHeight) / height;

		// Create a matrix for the manipulation

		// Resize the bit map
		matrix.postScale(scaleWidth, scaleHeight);

		// Recreate the new Bitmap
		invalidate();

	}

	/**
	 * sets beacon positions
	 * 
	 * @param positions
	 */
	public void setBeaconsPositions(Vector<BeaconRacun> positions) {
		beaconPositions = positions;
	}

	/**
	 * For drawing map
	 */
	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		canvas.save();

		height = getMeasuredHeight();
		width = getMeasuredWidth();

		ratio1 = height * 1.0f / mMap.getBounds().height();
		ratio2 = width * 1.0f / mMap.getBounds().width();
		// getResizedBitmap(mMap, height, width);

		scaleratio = Math.min(ratio1, ratio2);

		canvas.concat(matrix);
		canvas.scale(scaleratio, scaleratio);
		// mMap.setBounds(0, 0, 0, 0);
		// canvas.drawBitmap(((BitmapDrawable)mMap).getBitmap(), 0, 0, null);
		mMap.draw(canvas);
		
		mDot.draw(canvas);
		
		clipBounds = canvas.getClipBounds();

		for (BeaconView bc : listBeacona) {
			// Log.d("BIKON", bc.getPoruka());
			bc.draw(canvas);
		}

		canvas.restore();

	}

	public Rect getClipBound() {
		return clipBounds;
	}

	public void setClipBound(Rect clipBounds) {
		this.clipBounds = clipBounds;
	}

	/**
	 * Sets coordinates for dotView to (x, y)
	 * 
	 * @param x
	 * @param y
	 */
	public void setDotCoordinates(float x, float y) {
		mDot.setCoordinates(x, y);
		invalidate();
	}

	public void setMatrixTranslate(float x, float y) {
		matrix.postTranslate(x, y);
		invalidate();
	}

	/**
	 * 
	 * @return mDotView
	 */
	public DotView getDot() {
		return mDot;
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// Let the ScaleGestureDetector inspect all events.
		detector.onTouchEvent(ev);
		simpledetector.onTouchEvent(ev);
		return true;
	}

	SimpleOnGestureListener simpleOnGestureListener = new SimpleOnGestureListener() {

		@Override
		public boolean onDown(MotionEvent e) {

			return true;
		};

		@Override
		public boolean onDoubleTap(MotionEvent e) {
			matrix.reset();
			invalidate();
			return super.onDoubleTap(e);
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			// Make sure that mTextView is the text view you want to move around
			translatedX += distanceX;
			translatedY += distanceY;
			matrix.postTranslate(-distanceX, -distanceY);
			invalidate();
			return true;
		}
	};

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {

		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			matrix.postScale(detector.getScaleFactor(),
					detector.getScaleFactor(), detector.getFocusX(),
					detector.getFocusY());

			invalidate();

			return true;
		}

		@Override
		public boolean onScaleBegin(ScaleGestureDetector detector) {
			// TODO Auto-generated method stub
			return super.onScaleBegin(detector);
		}

		@Override
		public void onScaleEnd(ScaleGestureDetector detector) {
			// TODO Auto-generated method stub
			super.onScaleEnd(detector);
		}

	}

	public float getTranslatedX() {
		return translatedX;
	}

	public void setTranslatedX(float translatedX) {
		this.translatedX = translatedX;
	}

	public float getTranslatedY() {
		return translatedY;
	}

	public void setTranslatedY(float translatedY) {
		this.translatedY = translatedY;
	}

	public void translateCenterToDot() {
		// TODO Auto-generated method stub

		ValueAnimator va = ValueAnimator.ofFloat(0, 1);
		va.setDuration(500);
		// INTERPOLATOR
		for (int i = 0; i < 5; i++) {

			float oldX = getClipBound().centerX();
			float oldY = getClipBound().centerY();
			float newX = mDot.getxCoor();
			float newY = mDot.getyCoor();
			/*
			 * TranslateAnimation anim = new TranslateAnimation( oldX,
			 * oldX-mDot.getxCoor() , oldY, oldY-mDot.getyCoor() );
			 * anim.setDuration(1000); anim.setFillAfter( true );
			 * this.startAnimation(anim);
			 */
			matrix.postTranslate(oldX - mDot.getxCoor(), oldY - mDot.getyCoor());

			invalidate();
		}
		/*
		 * va.addUpdateListener(new AnimatorUpdateListener() {
		 * 
		 * @Override public void onAnimationUpdate(ValueAnimator animation) {
		 * float value = animation.getAnimatedFraction(); float dx = newX -
		 * oldX; float dy = newY - oldY; float currX = oldX + dx * value; float
		 * currY = oldY + dy * value; //Log.d(VIEW_LOG_TAG,
		 * ""+(getClipBound().centerX()-mDot.getxCoor())*value +" " +oldY);
		 * matrix.setTranslate(oldX
		 * +(getClipBound().centerX()-mDot.getxCoor())*value,
		 * oldY+(getClipBound().centerY()-mDot.getyCoor())*value); invalidate();
		 * } }); va.start();
		 */
	}

	public void rotate(float degree, float oldDegree) {
		float centerx = mMap.getBounds().centerX();
		float centery = mMap.getBounds().centerY();
		
		if(oldDegree < degree)
		{
			matrix.preRotate(-degree+oldDegree, centerx, centery);
			invalidate();
		}
		else if(oldDegree > degree)
		{
			matrix.preRotate(+oldDegree-degree, centerx, centery);
			invalidate();
		}
		
	}

}
